package com.xianniu.ltc.controller;

import cn.devezhao.persist4j.engine.ID;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.rebuild.core.Application;
import com.rebuild.core.UserContextHolder;
import com.rebuild.core.privileges.bizz.Department;
import com.rebuild.web.BaseController;
import com.xianniu.ltc.mapper.*;
import com.xianniu.ltc.model.entity.THuikuanjihuaDTO;
import com.xianniu.ltc.model.entity.TRbhetong0DTO;
import com.xianniu.ltc.model.entity.TRbhuikuandanDTO;
import com.xianniu.ltc.model.po.FinanceUncollectedPO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 商机控制器
 * @Author: dingyx
 * @Date: 2022/2/28 10:37 上午
 */
@RestController
@Slf4j
@RequestMapping(value = "/finance")
public class FinanceController extends BaseController {
    /**
     * 配置文件中我的qq邮箱
     */
    @Value("${report.contact.deptList}")
    private String deptListStr;
    @Resource
    private TRbhetong0Mapper tRbhetong0Mapper;
    @Resource
    private THuikuanjihuaMapper tHuikuanjihuaMapper;
    @Resource
    private THuikuandanMapper tHuikuandanMapper;
    /**
     * 四舍五入位数
     */
    private int scale = 2;
    /**
     * 月度模板
     */
    private static SimpleDateFormat dateFormat = new SimpleDateFormat( "yyyy-MM");

    private static List<String> over3Month;
    static {
        long startT = System.currentTimeMillis();
        List<String> recent3Month = new ArrayList<>();
        Date current = new Date();
        for(int index = 4; index <= 6000; index++){
            Date month = DateUtil.offsetMonth(current, -index);
            recent3Month.add(dateFormat.format(month));
        }
        long endT = System.currentTimeMillis();
        log.info("三个月耗时{}", (endT - startT));
        over3Month = recent3Month;
    }


    @PostMapping("/uncollectedByDept")
    public Map<String, Object> uncollectedByDept(@RequestBody FinanceUncollectedPO po){
        Map<String, Object> result = new HashMap<>();
        // 需要统计数据的部门
        String queryDeptName = po.getDeptName();
        String tenant = UserContextHolder.getTenant();
        Department[] departments = Application.getUserStore().getAllDepartments(tenant);
        Department queryDept = Arrays.stream(departments).filter(ca -> ca.getName().equals(queryDeptName)).findAny().orElse(null);
        if(Objects.isNull(queryDept)){
            // 部门不存在
            log.info("{}部门不存在", queryDeptName);
            return result;
        }
        QueryWrapper<TRbhetong0DTO> htWrapper = new QueryWrapper<>();
        htWrapper.eq("OWNING_DEPT", queryDept.getIdentity().toString());
        List<TRbhetong0DTO> htList = tRbhetong0Mapper.selectList(htWrapper);
        // 筛选销售合同ID集合
        List<String> htIds = htList.stream().map(TRbhetong0DTO::getRbhetong0Id).collect(Collectors.toList());
        // 1. 查询全部回款计划
        QueryWrapper<THuikuanjihuaDTO> jhWrapper = new QueryWrapper<>();
        jhWrapper.in("GUANLIANHETONG", htIds);
        jhWrapper.le("YUJIHUIKUANRIQI", DateUtil.endOfMonth(new Date()));
        List<THuikuanjihuaDTO> jhList = tHuikuanjihuaMapper.selectList(jhWrapper);
        // 回款计划ID集合
        List<String> jhIdList = jhList.stream().map(THuikuanjihuaDTO::getHuikuanjihuaId).collect(Collectors.toList());
        // 第一个维度，展示不同账龄应收
        Map<String, BigDecimal> collectedA = new HashMap<>();
        // 2. 查询全部回款单
        QueryWrapper<TRbhuikuandanDTO> danWrapper = new QueryWrapper<>();
        danWrapper.in("HUIKUANJIHUA_ID", jhIdList);
        List<TRbhuikuandanDTO> danList = tHuikuandanMapper.selectList(danWrapper);
        // 3. 根据 12 查询截止当前，全部应收未收
        BigDecimal totalUncollected = cal(jhList, danList);
        if(BigDecimal.ZERO.compareTo(totalUncollected) == 0){
            log.info("截至目前{} - 下全部应收为零，不记录", queryDeptName);
            return result;
        }
        // 4. 根据 12 查询近三个月应收未收
        BigDecimal dataIn3MonthUncollected = dataIn3Month(jhList, danList);
        // 5. 根据 12 查询超三个月应收未收
        BigDecimal dataOver3MonthUncollected = dataOver3Month(jhList, danList);
        // 6. 根据 12 查询本月应收未收
        BigDecimal currentMonthUncollected = currentData(jhList, danList);

        collectedA.put("totalUncollected", totalUncollected);
        collectedA.put("dataIn3MonthUncollected", dataIn3MonthUncollected);
        collectedA.put("dataOver3MonthUncollected", dataOver3MonthUncollected);
        collectedA.put("currentMonthUncollected", currentMonthUncollected);
        // 第二个维度，展示不同账龄应收占比
        Map<String, BigDecimal> collectedB = new HashMap<>();
        collectedB.put("dataIn3MonthRate", NumberUtil.div(NumberUtil.mul(dataIn3MonthUncollected, 100),  totalUncollected, scale));
        collectedB.put("dataOver3MonthRate", NumberUtil.div(NumberUtil.mul(dataOver3MonthUncollected, 100), totalUncollected, scale));
        collectedB.put("currentMonthRate", NumberUtil.div(NumberUtil.mul(currentMonthUncollected, 100), totalUncollected, scale));

        result.put("collectedA", collectedA);
        result.put("collectedB", collectedB);
        // 第四个维度，展示部门不同账龄应收详情
        Map<String, BigDecimal> collectedC = new HashMap<>();
        // 第三个维度，展示部门不同账龄应收占比
        List<Map<String, Object>> collectedD = new ArrayList<>();
        // 合同按照所属个人分组
        Map<String, List<TRbhetong0DTO>> deptMaps = htList.stream().collect(Collectors.groupingBy(TRbhetong0DTO::getOwningUser, Collectors.toList()));
        for(Map.Entry<String, List<TRbhetong0DTO>> deptMap : deptMaps.entrySet()){
            // 个人名称
            String name = Application.getUserStore().getUser(ID.valueOf(deptMap.getKey())).getFullName();
            // 个人合同集合
            List<TRbhetong0DTO> htInDeptList = deptMap.getValue();
            // 个人合同ID集合
            List<String> htInDeptIds = htInDeptList.stream().map(TRbhetong0DTO::getRbhetong0Id).collect(Collectors.toList());
            // 个人回款计划集合
            List<THuikuanjihuaDTO> jhInDeptList = jhList.stream().filter(ca -> htInDeptIds.contains(ca.getGuanlianhetong())).collect(Collectors.toList());
            // 个人回款计划ID集合
            List<String> jhInDeptIds = jhInDeptList.stream().map(THuikuanjihuaDTO::getHuikuanjihuaId).collect(Collectors.toList());
            // 个人回款单集合
            List<TRbhuikuandanDTO> danInDeptList = danList.stream().filter(ca -> jhInDeptIds.contains(ca.getHuikuanjihuaId())).collect(Collectors.toList());
            // 查询截止当前，部门下全部应收未收
            BigDecimal totalUncollectedInDept = cal(jhInDeptList, danInDeptList);
            if(BigDecimal.ZERO.compareTo(totalUncollectedInDept) == 0){
                log.info("截至目前{} - 下全部应收为零，不记录", name);
                continue;
            }
            // 查询近三个月应收未收
            BigDecimal dataIn3MonthInDeptUncollected = dataIn3Month(jhInDeptList, danInDeptList);
            // 查询超三个月应收未收
            BigDecimal dataOver3MonthUncollectedInDept = dataOver3Month(jhInDeptList, danInDeptList);
            // 查询本月应收未收
            BigDecimal currentMonthUncollectedInDept = currentData(jhInDeptList, danInDeptList);
            // 部门应收数据
            Map<String, Object> collectedADept = new HashMap<>();
            collectedADept.put("totalUncollected", totalUncollectedInDept);
            collectedADept.put("dataIn3MonthUncollected", dataIn3MonthInDeptUncollected);
            collectedADept.put("dataOver3MonthUncollected", dataOver3MonthUncollectedInDept);
            collectedADept.put("currentMonthUncollected", currentMonthUncollectedInDept);
            collectedADept.put("name", name);
            collectedD.add(collectedADept);

            collectedC.put(name, NumberUtil.div(NumberUtil.mul(totalUncollectedInDept, 100), totalUncollected, scale));
        }
        result.put("deptData", collectedD);
        result.put("collectedC", collectedC);
        return result;





    }

    @PostMapping("/uncollected")
    public Map<String, Object> payCollectionStatus(HttpServletRequest request) {
        Map<String, Object> result = new HashMap<>();
        // 第一个维度，展示不同账龄应收
        Map<String, BigDecimal> collectedA = new HashMap<>();

        // 1. 查询全部回款计划
        QueryWrapper<THuikuanjihuaDTO> jhWrapper = new QueryWrapper<>();
        jhWrapper.le("YUJIHUIKUANRIQI", DateUtil.endOfMonth(new Date()));
        List<THuikuanjihuaDTO> jhList = tHuikuanjihuaMapper.selectList(jhWrapper);
        // 2. 查询全部回款单
        QueryWrapper<TRbhuikuandanDTO> danWrapper = new QueryWrapper<>();
        List<TRbhuikuandanDTO> danList = tHuikuandanMapper.selectList(danWrapper);
        // 3. 根据 12 查询截止当前，全部应收未收
        BigDecimal totalUncollected = cal(jhList, danList);
        // 4. 根据 12 查询近三个月应收未收
        BigDecimal dataIn3MonthUncollected = dataIn3Month(jhList, danList);
        // 5. 根据 12 查询超三个月应收未收
        BigDecimal dataOver3MonthUncollected = dataOver3Month(jhList, danList);
        // 6. 根据 12 查询本月应收未收
        BigDecimal currentMonthUncollected = currentData(jhList, danList);
        // 根据1 筛选关联的销售合同集合
        List<String> htIds = jhList.stream().map(THuikuanjihuaDTO::getGuanlianhetong).collect(Collectors.toList());
        // 7. 查询回款计划关联的销售合同集合
        QueryWrapper<TRbhetong0DTO> htWrapper = new QueryWrapper<>();
        htWrapper.in("RBHETONG0_ID", htIds);
        List<TRbhetong0DTO> htList = tRbhetong0Mapper.selectList(htWrapper);

        collectedA.put("totalUncollected", totalUncollected);
        collectedA.put("dataIn3MonthUncollected", dataIn3MonthUncollected);
        collectedA.put("dataOver3MonthUncollected", dataOver3MonthUncollected);
        collectedA.put("currentMonthUncollected", currentMonthUncollected);
        // 第二个维度，展示不同账龄应收占比
        Map<String, BigDecimal> collectedB = new HashMap<>();
        collectedB.put("dataIn3MonthRate", NumberUtil.div(NumberUtil.mul(dataIn3MonthUncollected, 100), totalUncollected, scale));
        collectedB.put("dataOver3MonthRate", NumberUtil.div(NumberUtil.mul(dataOver3MonthUncollected, 100), totalUncollected, scale));
        collectedB.put("currentMonthRate", NumberUtil.div(NumberUtil.mul(currentMonthUncollected, 100), totalUncollected, scale));

        result.put("collectedA", collectedA);
        result.put("collectedB", collectedB);
        // 第四个维度，展示部门不同账龄应收详情
        Map<String, BigDecimal> collectedC = new HashMap<>();
        // 第三个维度，展示部门不同账龄应收占比
        List<Map<String, Object>> collectedD = new ArrayList<>();
        // 合同按照所属部门分组
        Map<String, List<TRbhetong0DTO>> deptMaps = htList.stream().collect(Collectors.groupingBy(TRbhetong0DTO::getOwningDept, Collectors.toList()));
        for(Map.Entry<String, List<TRbhetong0DTO>> deptMap : deptMaps.entrySet()){
            // 部门名称
            String name = Application.getUserStore().getDepartment(ID.valueOf(deptMap.getKey())).getName();
            // 部门合同集合
            List<TRbhetong0DTO> htInDeptList = deptMap.getValue();
            // 部门合同ID集合
            List<String> htInDeptIds = htInDeptList.stream().map(TRbhetong0DTO::getRbhetong0Id).collect(Collectors.toList());
            // 部门回款计划集合
            List<THuikuanjihuaDTO> jhInDeptList = jhList.stream().filter(ca -> htInDeptIds.contains(ca.getGuanlianhetong())).collect(Collectors.toList());
            // 部门回款计划ID集合
            List<String> jhInDeptIds = jhInDeptList.stream().map(THuikuanjihuaDTO::getHuikuanjihuaId).collect(Collectors.toList());
            // 部门回款单集合
            List<TRbhuikuandanDTO> danInDeptList = danList.stream().filter(ca -> jhInDeptIds.contains(ca.getHuikuanjihuaId())).collect(Collectors.toList());
            // 查询截止当前，部门下全部应收未收
            BigDecimal totalUncollectedInDept = cal(jhInDeptList, danInDeptList);
            if(BigDecimal.ZERO.compareTo(totalUncollectedInDept) == 0){
                log.info("截至目前{} - 下全部应收为零，不记录", name);
                continue;
            }
            // 查询近三个月应收未收
            BigDecimal dataIn3MonthInDeptUncollected = dataIn3Month(jhInDeptList, danInDeptList);
            // 查询超三个月应收未收
            BigDecimal dataOver3MonthUncollectedInDept = dataOver3Month(jhInDeptList, danInDeptList);
            // 查询本月应收未收
            BigDecimal currentMonthUncollectedInDept = currentData(jhInDeptList, danInDeptList);
            // 部门应收数据
            Map<String, Object> collectedADept = new HashMap<>();
            collectedADept.put("totalUncollected", totalUncollectedInDept);
            collectedADept.put("dataIn3MonthUncollected", dataIn3MonthInDeptUncollected);
            collectedADept.put("dataOver3MonthUncollected", dataOver3MonthUncollectedInDept);
            collectedADept.put("currentMonthUncollected", currentMonthUncollectedInDept);
            collectedADept.put("name", name);
            collectedD.add(collectedADept);

            collectedC.put(name, NumberUtil.div(NumberUtil.mul(totalUncollectedInDept, 100), totalUncollected, scale));
        }
        result.put("deptData", collectedD);
        result.put("collectedC", collectedC);
        return result;
    }

    /**
     * 最近三个月标示(不包括本月)
     * @return
     */
    private List<String> recent3Month() {
        List<String> recent3Month = new ArrayList<>();
        Date current = new Date();
        for(int index = 1; index <= 3; index++){
            Date month = DateUtil.offsetMonth(current, -index);
            recent3Month.add(dateFormat.format(month));
        }
        return recent3Month;
    }

    /**
     * 计算本月应收未收
     * @param jhInDeptList
     * @param danInDeptList
     * @return
     */
    private BigDecimal currentData(List<THuikuanjihuaDTO> jhInDeptList, List<TRbhuikuandanDTO> danInDeptList) {
        Date current = new Date();
        // 查询本月应收未收
        List<THuikuanjihuaDTO> jhCurrentMonthInDept = jhInDeptList.stream().
                filter(ca -> dateFormat.format(ca.getYujihuikuanriqi()).equals(dateFormat.format(current))).
                collect(Collectors.toList());
        List<String> jhIdsCurrentMonthInDept = jhCurrentMonthInDept.stream().map(THuikuanjihuaDTO::getHuikuanjihuaId).collect(Collectors.toList());
        List<TRbhuikuandanDTO> danCurrentMonthInDept = danInDeptList.stream().
                filter(ca -> jhIdsCurrentMonthInDept.contains(ca.getHuikuanjihuaId())).
                collect(Collectors.toList());
        return cal(jhCurrentMonthInDept, danCurrentMonthInDept);
    }

    /**
     * 计算超三个月应收未收
     * @param jhList
     * @param danList
     * @return
     */
    private BigDecimal dataOver3Month(List<THuikuanjihuaDTO> jhList, List<TRbhuikuandanDTO> danList) {
        List<THuikuanjihuaDTO> jhOverThreeMonth = jhList.stream().
                filter(ca -> over3Month.contains(dateFormat.format(ca.getYujihuikuanriqi()))).
                collect(Collectors.toList());
        List<String> jhIdsOverThreeMonth = jhOverThreeMonth.stream().map(THuikuanjihuaDTO::getHuikuanjihuaId).collect(Collectors.toList());
        List<TRbhuikuandanDTO> danOverThreeMonth = danList.stream().
                filter(ca -> jhIdsOverThreeMonth.contains(ca.getHuikuanjihuaId())).
                collect(Collectors.toList());
        return cal(jhOverThreeMonth, danOverThreeMonth);
    }

    /**
     * 统计近三个月应收未收
     * @param jhList
     * @param danList
     * @return
     */
    private BigDecimal dataIn3Month(List<THuikuanjihuaDTO> jhList, List<TRbhuikuandanDTO> danList) {
        List<THuikuanjihuaDTO> jhInThreeMonth = jhList.stream().
                filter(ca -> recent3Month().contains(dateFormat.format(ca.getYujihuikuanriqi()))).
                collect(Collectors.toList());
        List<String> jhIdsInThreeMonth = jhInThreeMonth.stream().map(THuikuanjihuaDTO::getHuikuanjihuaId).collect(Collectors.toList());
        List<TRbhuikuandanDTO> danInThreeMonth = danList.stream().
                filter(ca -> jhIdsInThreeMonth.contains(ca.getHuikuanjihuaId())).
                collect(Collectors.toList());
        return cal(jhInThreeMonth, danInThreeMonth);
    }

    /**
     * 根据回款计划跟回款单计算应收未收金额
     * @param jhList 回款计划列表
     * @param danList 回款单列表
     * @return
     */
    private BigDecimal cal(List<THuikuanjihuaDTO> jhList, List<TRbhuikuandanDTO> danList){
        BigDecimal result = BigDecimal.ZERO;
        // 计划收款之和
        BigDecimal jhAmount =  jhList.stream().map(THuikuanjihuaDTO::getJihuashoukuanjine).
                        reduce(BigDecimal.ZERO, BigDecimal::add);
        // 回款单实际回款之和
        BigDecimal danAmount =  danList.stream().map(TRbhuikuandanDTO::getHuikuanjine).
                reduce(BigDecimal.ZERO, BigDecimal::add);
        return NumberUtil.sub(jhAmount, danAmount);
    }
}
